package com.ls.lsbase.net;

import android.support.v4.util.ArrayMap;

import com.google.gson.Gson;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by linshao on 2017/3/29.
 */

public class HttpUtils {
    private static OkHttpClient okHttpClient;
    private static Gson gson;
    public final static String IP = "";//you must config this IP
    private static Call call;
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

    private static OkHttpClient getOkHttpClient() {
        if (null == okHttpClient) {
            okHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(10, TimeUnit.SECONDS)
                    .writeTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(10, TimeUnit.SECONDS)
                    .build();
        }
        return okHttpClient;
    }

    private static Gson getGson() {
        if (null == gson) {
            gson = new Gson();
        }
        return gson;
    }

    /**
     * simple get
     *
     * @param url
     * @param call
     */
    public static <T> void get(final String url, final CallBack<T> call) {
        Request request = new Request.Builder().url(getRealUrl(url)).build();
        realConnect(request, call);
    }

    /**
     * get method with maps
     *
     * @param url
     * @param maps
     * @param call
     */
    public static <T> void get(final String url, ArrayMap<String, String> maps, final CallBack<T> call) {
        String tempUrl = getRealUrl(url);
        if (null != maps && !maps.isEmpty()) {
            for (Map.Entry<String, String> entry : maps.entrySet()) {
                tempUrl += url.contains("?") ? "&" : "?";
                tempUrl += entry.getKey() + "=" + entry.getValue();
            }
        }
        Request request = new Request.Builder().url(tempUrl).build();
        realConnect(request, call);
    }

    /**
     * simple post(no body)
     *
     * @param url
     * @param call
     */
    public static <T> void post(final String url, final CallBack<T> call) {
        postMap(url, null, call);
    }

    /**
     * post method (with maps)
     *
     * @param url
     * @param maps
     * @param call
     */
    public static <T> void postMap(final String url, ArrayMap<String, String> maps, final CallBack<T> call) {
        FormBody.Builder formBuilder = new FormBody.Builder();
        Request request;
        if (null != maps && !maps.isEmpty()) {
            for (Map.Entry<String, String> entry : maps.entrySet()) {
                formBuilder.add(entry.getKey(), entry.getValue());
            }
        }
        request = new Request.Builder().url(getRealUrl(url)).post(formBuilder.build()).build();
        realConnect(request, call);
    }

    /**
     * post method (can post files imgs)
     *
     * @param url
     * @param builder
     * @param call
     */
    public static <T> void postForm(final String url, FormBody.Builder builder, final CallBack<T> call) {
        Request request = new Request.Builder().url(getRealUrl(url)).post(builder.build()).build();
        realConnect(request, call);
    }

    public static <T> void postRequestBody(final String url, RequestBody body, final CallBack<T> call) {
        Request request = new Request.Builder().url(getRealUrl(url)).post(body).build();
        realConnect(request, call);
    }

    public static <T> void postJson(final String url, Object o, final CallBack<T> call) {
        Request request = new Request.Builder().url(getRealUrl(url)).post(RequestBody.create(JSON, new Gson().toJson(o))).build();
        realConnect(request, call);
    }

    /**
     * really net method
     *
     * @param request
     * @param calls
     */
    private static <T> void realConnect(final Request request, final CallBack<T> calls) {
        calls.start();
        getOkHttpClient().newCall(request).enqueue(new Callback() {
            public void onFailure(Call call, IOException ioException) {
                calls.failuer(ioException.getMessage());
            }

            public void onResponse(Call c, Response response) throws IOException {
                int code = response.code();
                if (code == 200) {
                    Type type = ((ParameterizedType) call.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
                    if (type.toString().equals("class java.lang.Object")) {
                        calls.success(null);
                    } else {
                        T ty = getGson().fromJson(response.body().string(), type);
                        calls.success(ty);
                    }
                } else {
                    calls.failuer(String.valueOf(code));
                }
            }
        });
    }

    /**
     * get full url
     *
     * @param url
     * @return
     */
    private static String getRealUrl(String url) {
        if (url.startsWith("http")) {
            return url;
        } else {
            return IP + url;
        }
    }

    public static void cancle() {
        if (null != call && !call.isExecuted()) {
            call.cancel();
        }
    }
}
